package tuling.design.mode.prototype;



/**
 * 原型模式
 * 作用：不耦合的复制初始化后的对象
 *      避免重复初始化对象
 *      简单的说就是解决对象复制
 */
public class PrototypeTest {
    public static void main(String[] args) {
        Product product = new Product("箱水", 20, new BaseInfo("化妆品"));
        Product clone = product.clone();
        System.out.println("原对象： " + product);
        System.out.println("克隆对象： " + clone);
        System.out.println("修改原对象baseinfo数据：");
        product.setBaseInfo(new BaseInfo("电子产品"));
        product.setProName("香水");
        System.out.println("原对象： " + product);
        System.out.println("克隆对象： " + clone);
        System.out.println("原对象数据发生改变，克隆对象数据没有发生改变。。。解耦合");
    }
}

/**
 * 实现原型：
 * 1、实现Cloneable(克隆)接口
 * 2、如果属性是对象（不被final信息）也需要实现接口
 * 3、java自己的数据类型不会与克隆对象耦合 但是自己引用的对象会所以需要对引用对象做处理
 */
class Product implements Cloneable{
    private String proName;
    private Integer num;
    private BaseInfo baseInfo;

    public Product(String proName, Integer num, BaseInfo baseInfo) {
        this.proName = proName;
        this.num = num;
        this.baseInfo = baseInfo;
    }

    @Override
    public String toString() {
        return this.hashCode()+" : "+"Product{" +
                "proName='" + proName + '\'' +
                ", num=" + num +
                ", baseInfo=" + baseInfo +
                '}';
    }

    public String getProName() {
        return proName;
    }

    public void setProName(String proName) {
        this.proName = proName;
    }

    public Integer getNum() {
        return num;
    }

    public void setNum(Integer num) {
        this.num = num;
    }

    public BaseInfo getBaseInfo() {
        return baseInfo;
    }

    public void setBaseInfo(BaseInfo baseInfo) {
        this.baseInfo = baseInfo;
    }

    /**
     *重写 克隆方法 同时对象引用BaseInfo 需要重新调用它自己的clone的方法
     */
    @Override
    public Product clone() {
        try {
            Product clone = (Product) super.clone();
            //处理被克隆对象和克隆后对象baseInfo引用地址一样 造成数据一样的问题
            BaseInfo baseInfo1 = this.baseInfo.clone();
            clone.setBaseInfo(baseInfo1);
            return clone;
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }
}

class BaseInfo implements Cloneable{
    private String tagName;

    public BaseInfo(String tagName) {
        this.tagName = tagName;
    }

    @Override
    public String toString() {
        return this.hashCode()+" : "+"BaseInfo{" +
                "tagName='" + tagName + '\'' +
                '}';
    }

    public String getTagName() {
        return tagName;
    }

    public void setTagName(String tagName) {
        this.tagName = tagName;
    }

    /**
     * 重写克隆方法
     */
    @Override
    public BaseInfo clone() {
        try {
            return (BaseInfo) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }
}